//! 模块系统示例
//!
//! Rust 提供了强大的模块系统来帮助组织代码。模块系统允许我们将代码组织成不同的逻辑单元，
//! 控制代码的可见性，并在不同的文件和 crate 之间重用代码。

/// 模块基础
///
/// 模块允许我们将代码组织成不同的逻辑单元
pub fn module_basics() {
    println!("=== 模块基础 ===");

    // 在 Rust 中，模块是用于组织代码的容器
    // 模块可以包含函数、结构体、枚举、常量、特征以及其他模块

    // 定义一个模块
    mod sound {
        pub mod instrument {
            pub fn guitar() {
                println!("演奏吉他");
            }

            pub fn piano() {
                println!("演奏钢琴");
            }
        }

        pub mod voice {
            pub fn sing() {
                println!("唱歌");
            }
        }
    }

    // 使用模块中的函数
    sound::instrument::guitar();
    sound::instrument::piano();
    sound::voice::sing();
}

/// 可见性控制
///
/// Rust 默认所有项都是私有的，使用 pub 关键字可以使其变为公有
pub fn visibility_control() {
    println!("\n=== 可见性控制 ===");

    mod outer {
        // 默认是私有的，只能在当前模块内访问
        fn private_function() {
            println!("这是私有函数");
        }

        // 使用 pub 关键字使其变为公有的
        pub fn public_function() {
            println!("这是公有函数");
            private_function(); // 私有函数可以在同一模块内访问
        }

        mod inner {
            // 在父模块中无法直接访问此函数
            pub fn accessible_in_parent() {
                println!("可以在父模块中通过 super 访问");
            }
        }

        // 使用 super 访问父模块
        pub fn call_inner() {
            // inner 模块是私有的，但其中的函数是公有的
            inner::accessible_in_parent();
        }
    }

    // 只能访问公有函数
    outer::public_function();
    outer::call_inner();
    // outer::private_function(); // 这会导致编译错误
}

/// use 关键字和模块导入
///
/// use 关键字允许我们将模块路径引入当前作用域
pub fn using_use_keyword() {
    println!("\n=== use 关键字和模块导入 ===");

    mod sound {
        pub mod instrument {
            pub fn guitar() {
                println!("弹吉他");
            }

            pub fn piano() {
                println!("弹钢琴");
            }
        }
    }

    // 不使用 use 关键字，需要完整路径
    sound::instrument::guitar();
    sound::instrument::piano();

    // 使用 use 关键字引入模块
    use sound::instrument::guitar;
    guitar(); // 现在可以直接调用

    // 引入多个项
    use sound::instrument::{guitar as g, piano};
    g();
    piano();

    // 引入整个模块
    use sound::instrument;
    instrument::guitar();
    instrument::piano();

    // 使用通配符引入所有公有项
    use sound::instrument::*;
    guitar();
    piano();
}

/// pub use 重新导出
///
/// pub use 允许我们将其他位置定义的项重新导出到当前模块
pub fn pub_use_reexports() {
    println!("\n=== pub use 重新导出 ===");

    mod front_house {
        pub mod hosting {
            pub fn add_to_waitlist() {
                println!("添加到等候列表");
            }

            pub fn seat_at_table() {
                println!("安排座位");
            }
        }
    }

    mod back_house {
        pub struct Breakfast {
            pub toast: String,
            seasonal_fruit: String, // 私有字段
        }

        impl Breakfast {
            pub fn summer(toast: &str) -> Breakfast {
                Breakfast {
                    toast: String::from(toast),
                    seasonal_fruit: String::from("桃子"),
                }
            }
        }

        pub enum Appetizer {
            Soup,
            Salad,
        }
    }

    // 使用 pub use 重新导出，创建更方便的公共 API
    pub use back_house::{Appetizer, Breakfast};
    pub use front_house::hosting;

    // 现在可以直接使用这些项
    hosting::add_to_waitlist();

    let mut meal = Breakfast::summer("全麦");
    meal.toast = String::from("小麦");
    println!("吐司: {}", meal.toast);

    let order1 = Appetizer::Soup;
    let order2 = Appetizer::Salad;
}

/// 模块文件结构
///
/// Rust 支持多种模块文件组织方式
pub fn module_file_structure() {
    println!("\n=== 模块文件结构 ===");

    // 1. 在同一个文件中定义模块（如当前文件）
    // 2. 在单独的文件中定义模块
    // 3. 在子目录中定义模块（使用 mod.rs 或 .rs 文件）

    println!("模块可以组织为:");
    println!("1. 同一文件中的内联模块");
    println!("2. 单独的 .rs 文件");
    println!("3. 带有 mod.rs 的目录模块");

    // 示例结构:
    // src/
    // ├── main.rs
    // ├── module.rs
    // └── nested/
    //     ├── mod.rs
    //     └── inner.rs
}

/// 模块可见性对比表
///
/// 展示不同可见性关键字的效果
pub fn visibility_comparison() {
    println!("\n=== 模块可见性对比 ===");

    struct VisibilityExample;

    impl VisibilityExample {
        // 私有方法，只能在当前模块内访问
        fn private_method() {
            println!("私有方法");
        }

        // 公有方法，可以在任何地方访问
        pub fn public_method() {
            println!("公有方法");
            // 可以调用私有方法
            Self::private_method();
        }

        // 受限制的可见性 (Rust 2018+)
        pub(crate) fn crate_method() {
            println!("仅在当前 crate 内可见");
        }

        // 对特定父模块路径可见
        pub(in crate::basic) fn basic_method() {
            println!("仅在 basic 模块内可见");
        }
    }

    // 调用各种可见性的方法
    VisibilityExample::public_method();
    VisibilityExample::crate_method();
    VisibilityExample::basic_method();
}

/// 模块系统最佳实践
///
/// 展示模块系统的推荐使用方式
pub fn module_best_practices() {
    println!("\n=== 模块系统最佳实践 ===");

    println!("1. 将相关的功能组织在同一个模块中");
    println!("2. 使用 pub 控制接口的可见性");
    println!("3. 使用 pub use 重新导出创建方便的公共 API");
    println!("4. 合理使用 use 关键字避免过长的路径");
    println!("5. 遵循 Rust 社区的文件组织规范");
    println!("6. 为模块添加文档注释说明其功能");

    // 模块可见性对比表
    println!("\n模块可见性对比表:");
    println!("| 可见性        | 作用域              | 语法示例              |");
    println!("|-------------|-------------------|---------------------|");
    println!("| 私有          | 当前模块             | fn function()       |");
    println!("| 公有          | 任何地方             | pub fn function()   |");
    println!("| crate内可见    | 当前 crate         | pub(crate) fn func()|");
    println!("| 指定路径内可见    | 指定模块路径         | pub(in path) fn func()|");
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_module_basics() {
        module_basics();
    }

    #[test]
    fn test_visibility_control() {
        visibility_control();
    }

    #[test]
    fn test_using_use_keyword() {
        using_use_keyword();
    }

    #[test]
    fn test_pub_use_reexports() {
        pub_use_reexports();
    }

    #[test]
    fn test_module_file_structure() {
        module_file_structure();
    }

    #[test]
    fn test_visibility_comparison() {
        visibility_comparison();
    }

    #[test]
    fn test_module_best_practices() {
        module_best_practices();
    }
}
